// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#pragma once

#include <pollux/core/plan_node.h>

namespace kumo::pollux::sql {
    class ReferenceQueryRunner;

    /// Appends a comma to a given stringstream if the provided integer is greater
    /// than 0.
    void appendComma(int32_t i, std::stringstream &sql);

    /// Return the SQL string of type.
    std::string toTypeSql(const TypePtr &type);

    /// Converts input expressions into SQL string and appends to a given
    /// stringstream.
    void toCallInputsSql(
        const std::vector<core::TypedExprPtr> &inputs,
        std::stringstream &sql);

    /// Converts a call expression into a SQL string.
    std::string toCallSql(const core::CallTypedExprPtr &call);

    /// Convert a cast expression into a SQL string.
    std::string toCastSql(const core::CastTypedExpr &cast);

    /// Convert a concat expression into a SQL string.
    std::string toConcatSql(const core::ConcatTypedExpr &concat);

    /// Convert a constant expression into a SQL string.
    ///
    /// Constant expressions of complex types, timestamp with timezone, interval,
    /// and decimal types are not supported yet.
    std::string toConstantSql(const core::ConstantTypedExpr &constant);

    // Converts aggregate call expression into a SQL string.
    std::string toAggregateCallSql(
        const core::CallTypedExprPtr &call,
        const std::vector<core::FieldAccessTypedExprPtr> &sortingKeys,
        const std::vector<core::SortOrder> &sortingOrders,
        bool distinct);

    class PrestoSqlPlanNodeVisitorContext : public core::PlanNodeVisitorContext {
    public:
        std::optional<std::string> sql;
    };

    class PrestoSqlPlanNodeVisitor : public core::PlanNodeVisitor {
    public:
        explicit PrestoSqlPlanNodeVisitor(ReferenceQueryRunner *queryRunner)
            : queryRunner_(queryRunner) {
        }

        void visit(const core::HashJoinNode &node, core::PlanNodeVisitorContext &ctx)
        const override;

        void visit(
            const core::NestedLoopJoinNode &node,
            core::PlanNodeVisitorContext &ctx) const override;

        void visit(const core::TableScanNode &node, core::PlanNodeVisitorContext &ctx)
        const override;

        void visit(const core::ValuesNode &node, core::PlanNodeVisitorContext &ctx)
        const override;

    protected:
        std::optional<std::string> toSql(const core::PlanNodePtr &node) const;

        ReferenceQueryRunner *queryRunner_;
    };
} // namespace kumo::pollux::sql
